﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks;
using GmailMetroNotifier.Client.Common;
using GmailMetroNotifier.Client.Properties;
using GmailMetroNotifier.Client.UI;

namespace GmailMetroNotifier.Client.Business
{
    /// <summary>
    /// Provides an <see cref="ICredentialsManager"/> implementation using the filesystem to
    /// load and save credentials.
    /// </summary>
    public class CredentialsManager : ICredentialsManager
    {
        private const char CredentialSeparator = ':';

        private Dictionary<string, NetworkCredential> _credentialsDictionary = new Dictionary<string, NetworkCredential>();

        /// <summary>
        /// Gets the collection of credentials stored.
        /// </summary>
        public IEnumerable<NetworkCredential> Credentials
        {
            get { return this._credentialsDictionary.Values; }
        }

        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        public CredentialsManager()
        {
            this.LoadCredentials();
        }

        /// <summary>
        /// Adds or updates the given credential to the storage.
        /// </summary>
        /// <param name="credential">The credential to be added or updated.</param>
        /// <exception cref="ArgumentNullException">Thrown when the given credential is null.</exception>
        /// <exception cref="ArgumentException">Thrown when no username is included in the given credential.</exception>
        public void AddOrUpdateCredentials(NetworkCredential credential)
        {
            if (credential == null)
            {
                throw new ArgumentNullException("credential");
            }

            if (string.IsNullOrWhiteSpace(credential.UserName))
            {
                throw new ArgumentException(Resources.EXCEPTION_MSG_CREDENTIAL_USERNAME_INVALID);
            }

            this._credentialsDictionary[credential.UserName] = credential;
        }

        private void LoadCredentials()
        {
            string credentialsFilePath = Constants.Paths.CredentialsFullPath;

            if (File.Exists(credentialsFilePath))
            {
                string[] credentials = File.ReadAllLines(credentialsFilePath);

                foreach (string credentialEntry in credentials)
                {
                    string[] credentialPieces = credentialEntry.Split(CredentialSeparator);

                    NetworkCredential credential = new NetworkCredential(credentialPieces[0], credentialPieces[1]);

                    this._credentialsDictionary.Add(credential.UserName, credential);
                }

            }
        }

        /// <summary>
        /// Saves the stored credentials.
        /// </summary>
        public void SaveCredentials()
        {
            string credentialsFilePath = Constants.Paths.CredentialsFullPath;

            string credentialsFileDirectory = Path.GetDirectoryName(credentialsFilePath);

            if (!Directory.Exists(credentialsFileDirectory))
            {
                Directory.CreateDirectory(credentialsFileDirectory);
            }

            List<string> serializedCredentials = new List<string>();

            serializedCredentials.AddRange(this._credentialsDictionary.Select(credential =>
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "{0}{1}{2}", 
                        credential.Value.UserName, 
                        CredentialSeparator, 
                        credential.Value.Password)));

            File.WriteAllLines(credentialsFilePath, serializedCredentials);
        }
    }
}
